/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ftpdownload;

import com.ice.tar.TarEntry;
import com.ice.tar.TarInputStream;
import dao.AccuracyLevelsDao;
import dao.FtpInfoCrud;
import dao.ProviderDao;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import pojo.AccuracyLevels;
import pojo.FtpInfo;
import pojo.Provider;

/**
 *
 * @author A7med Kotb
 */
//class that connect to FTP server and Get Supplier Files.
public class FtpDownload {

    private String providerName;
    static FtpInfo ftpinfo = null;
    Connection c;
    private String NowDate;
    private static String localFilePath;
    private static String FiNa;
    private static String newName;

    public FtpDownload(String ProviderName) {
        this.providerName = ProviderName;
        FTPClient client = new FTPClient();
        FileOutputStream fos = null;
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        Calendar cal = Calendar.getInstance();
        NowDate = dateFormat.format(cal.getTime());
        System.out.println("Date Now is : " + NowDate);
        try {
            DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dbuilder = dfactory.newDocumentBuilder();
            Document xmldocument = null;
            if (OSDetector.isWindows()) {
                xmldocument = dbuilder.parse("C:/Users/A7med Kotb/Documents/NetBeansProjects/trunk/Book Dimension Project/src/java/Configuration/winconfig.xml");
            }
            if (OSDetector.isUnix()) {
                xmldocument = dbuilder.parse("/home/ahmed/NetBeansProjects/trunk/Book Dimension Project/src/java/Configuration/linconfig.xml");
            }
            Element settingelement = xmldocument.getDocumentElement();
            Element mysqlUrlElement = (Element) settingelement.getElementsByTagName("mysql-url").item(0);
            Element mysqlUserNameElement = (Element) settingelement.getElementsByTagName("mysql-user-name").item(0);
            Element mysqlPasswordElement = (Element) settingelement.getElementsByTagName("mysql-password").item(0);
            String mysqlUrl = mysqlUrlElement.getTextContent();
            String mysqlUserName = mysqlUserNameElement.getTextContent();
            String mysqlPassword = mysqlPasswordElement.getTextContent();
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            c = DriverManager.getConnection(mysqlUrl, mysqlUserName, mysqlPassword);

            // get provider information and ftp information
            ProviderDao pdao = new ProviderDao(c);
            FtpInfoCrud ftpcrud = new FtpInfoCrud();
            Provider p = pdao.getByName(ProviderName);
            ftpinfo = ftpcrud.selectById(p.getPId());

            client.connect(ftpinfo.getHost());
            int reply = client.getReplyCode();
            if (client.isConnected()) {
                LogFile.log(" System ", " Connected to the FTP Server [" + ftpinfo.getHost() + "]Successfully .");
                if (client.login(ftpinfo.getUserName(), ftpinfo.getPassword())) {
                    LogFile.log(" System ", " logged Successfully into the FTP Server [" + ftpinfo.getHost() + "] with user name [" + ftpinfo.getUserName() + "] and Password [" + ftpinfo.getPassword() + "]");
                    client.cwd(ftpinfo.getRemoteDir());
                    client.setFileType(FTP.ASCII_FILE_TYPE);
                    String sep = null;
                    if (ftpinfo.getRemoteDir().startsWith("/")) {
                        sep = "/";
                    } else {
                        sep = "\\";
                    }
                    String remoteFilePath = ftpinfo.getRemoteDir() + sep + ftpinfo.getFileName() + "." + ftpinfo.getFileExtension();
                    localFilePath = ftpinfo.getLocalDir() + File.separator + ftpinfo.getFileName() + "." + ftpinfo.getFileExtension();
                    System.out.println("Remote File Path is : " + remoteFilePath);
                    System.out.println("Local File Path is : " + localFilePath);

                    String remoteLastModified = client.getModificationTime(ftpinfo.getFileName() + "." + ftpinfo.getFileExtension());
                    System.out.println("Remote File Last Modification Time is : " + remoteLastModified);

                    String absDate = remoteLastModified.substring(4, remoteLastModified.length());
                    SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddhhmmss");
                    Date d = formatter.parse(absDate);
                    DateFormat form = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    String formattedDate = form.format(d);
                    System.out.println("Remote File Last Modification Time after Formatting is  : " + formattedDate);
                    Date remoteLastModifiedDate = form.parse(formattedDate);

                    String savedDate = ftpinfo.getDateMod();
                    System.out.println("Last Saved Date is : " + savedDate);
                    String providerFile = localFilePath.replace("\\", "/");
                    if (savedDate.equalsIgnoreCase("null")) {
                        LogFile.log(" System ", " found that this is the first time to Download this file,file Name is [" + ftpinfo.getFileName() + "]");
                        fos = new FileOutputStream(ftpinfo.getLocalDir() + File.separator + ftpinfo.getFileName() + "." + ftpinfo.getFileExtension());
                        LogFile.log(" System ", " started Downloading File from FTP server with IP [" + ftpinfo.getHost() + "] , and File Name is [" + ftpinfo.getFileName() + "]");
                        if (client.retrieveFile(ftpinfo.getFileName() + "." + ftpinfo.getFileExtension(), fos)) {
                            LogFile.log(" System ", " Successfully Finished Downloading File[" + ftpinfo.getFileName() + "] from FTP server with IP [" + ftpinfo.getHost() + "], and save it with New Name [" + ftpinfo.getFileName() + "]");
                            ftpinfo.setDateMod(formattedDate);
                            ftpcrud.update(ftpinfo, ftpinfo.getFtpId());
                            /*
                             * unZipping Comming...
                             */
                            if (localFilePath.substring(localFilePath.lastIndexOf(".") + 1, localFilePath.lastIndexOf(".") + 3).equalsIgnoreCase("gz")) {
                                LogFile.log(" System ", " found that the type of file [" + ftpinfo.getFileName() + "] is GZ and Now will try to Extract it .");
                                InputStream in = new GZIPInputStream(new FileInputStream(new File(localFilePath)));
                                untar(in, ftpinfo.getLocalDir());
                            } else {
                                if (localFilePath.substring(localFilePath.lastIndexOf(".") + 1, localFilePath.lastIndexOf(".") + 4).equalsIgnoreCase("zip")) {
                                    LogFile.log(" System ", " found that the type of file [" + ftpinfo.getFileName() + "] is ZIP and Now will try to Extract it .");
                                    unZipFiles(localFilePath);
                                } else {
                                    if (localFilePath.substring(localFilePath.lastIndexOf(".") + 1, localFilePath.lastIndexOf(".") + 4).equalsIgnoreCase("tar")) {
                                        LogFile.log(" System ", " found that the type of file [" + ftpinfo.getFileName() + "] is TAR and Now will try to Extract it .");
                                        untarBaseUpgradeFile(localFilePath, ftpinfo.getLocalDir());
                                    }//unzipped file 
                                    else {
                                        FiNa = localFilePath;
                                        String FileExt = FiNa.substring(FiNa.lastIndexOf("."), FiNa.length());
                                        String reqNam = providerName + NowDate + FileExt;
                                        newName = ftpinfo.getLocalDir() + File.separator + reqNam;
                                    }
                                }
                            }
                            ScriptRunner sr = new ScriptRunner(c, true, false);
                            if (p.getType().equalsIgnoreCase("book")) {
                                Element commonelement = (Element) settingelement.getElementsByTagName("common-path").item(0);
                                Element estimationelement = (Element) settingelement.getElementsByTagName("estimation-path").item(0);
                                String estimationpath = estimationelement.getTextContent();
                                String commonpath = commonelement.getTextContent();
                                Element provscriptelement = (Element) settingelement.getElementsByTagName("book-script-files-path").item(0);
                                String provscriptpath = provscriptelement.getTextContent();
                                AccuracyLevels al = updateacclevels(p.getPId());
                                sr.runScript(new FileReader(provscriptpath + File.separator + p.getScriptPath()), ProviderName + "_dim", providerFile);
                                sr.runCommonScript(new FileReader(commonpath), ProviderName + "_dim", al);
                                sr.runEstimationScript(new FileReader(estimationpath), ProviderName + "_dim");
                            } else {
                                Element commonelement = (Element) settingelement.getElementsByTagName("media-common-path").item(0);
                                String commonpath = commonelement.getTextContent();
                                Element provscriptelement = (Element) settingelement.getElementsByTagName("media-script-files-path").item(0);
                                String provscriptpath = provscriptelement.getTextContent();
                                AccuracyLevels al = updateacclevels(p.getPId());
                                sr.runScript(new FileReader(provscriptpath + File.separator + p.getScriptPath()), ProviderName + "_dim", providerFile);
                                sr.runCommonScript(new FileReader(commonpath), ProviderName + "_dim", al);
                            }
                        } else {
                            LogFile.log(" System ", " Failed to Complete the operation of downloading the file [" + ftpinfo.getFileName() + "]");
                        }
                    } else {
                        Date savedDateinDB = form.parse(savedDate);
                        if (remoteLastModifiedDate.after(savedDateinDB)) {
                            LogFile.log(" System ", " found the Remote File has been Changed After Last Time it was Downloaded");
                            fos = new FileOutputStream(ftpinfo.getLocalDir() + File.separator + ftpinfo.getFileName() + "." + ftpinfo.getFileExtension());
                            LogFile.log(" System ", " started Downloading File from FTP server with IP [" + ftpinfo.getHost() + "] , and File Name is [" + ftpinfo.getFileName() + "]");
                            if (client.retrieveFile(ftpinfo.getFileName() + "." + ftpinfo.getFileExtension(), fos)) {
                                LogFile.log(" System ", " Successfully Finished Downloading File[" + ftpinfo.getFileName() + "] from FTP server with IP [" + ftpinfo.getHost() + "], and save it with New Name [" + ftpinfo.getFileName() + "]");
                                ftpinfo.setDateMod(formattedDate);
                                ftpcrud.update(ftpinfo, ftpinfo.getFtpId());
                                /*
                                 * unZipping Comming...
                                 */
                                if (localFilePath.substring(localFilePath.lastIndexOf(".") + 1, localFilePath.lastIndexOf(".") + 3).equalsIgnoreCase("gz")) {
                                    LogFile.log(" System ", " found that the type of file [" + ftpinfo.getFileName() + "] is GZ and Now will try to Extract it .");
                                    InputStream in = new GZIPInputStream(new FileInputStream(new File(localFilePath)));
                                    untar(in, ftpinfo.getLocalDir());
                                } else {
                                    if (localFilePath.substring(localFilePath.lastIndexOf(".") + 1, localFilePath.lastIndexOf(".") + 4).equalsIgnoreCase("zip")) {
                                        LogFile.log(" System ", " found that the type of file [" + ftpinfo.getFileName() + "] is ZIP and Now will try to Extract it .");
                                        unZipFiles(ftpinfo.getLocalDir() + File.separator + ftpinfo.getFileName() + "." + ftpinfo.getFileExtension());
                                    } else {
                                        if (localFilePath.substring(localFilePath.lastIndexOf(".") + 1, localFilePath.lastIndexOf(".") + 4).equalsIgnoreCase("tar")) {
                                            LogFile.log(" System ", " found that the type of file [" + ftpinfo.getFileName() + "] is TAR and Now will try to Extract it .");
                                            untarBaseUpgradeFile(localFilePath, ftpinfo.getLocalDir());
                                        } //un zipped file        
                                        else {
                                            FiNa = localFilePath;
                                            String FileExt = FiNa.substring(FiNa.lastIndexOf("."), FiNa.length());
                                            String reqNam = providerName + NowDate + FileExt;
                                            newName = ftpinfo.getLocalDir() + File.separator + reqNam;
                                        }
                                    }
                                }

                                //parsing XML
                                ScriptRunner sr = new ScriptRunner(c, true, false);
                                if (p.getType().equalsIgnoreCase("book")) {
                                    Element commonelement = (Element) settingelement.getElementsByTagName("common-path").item(0);
                                    Element estimationelement = (Element) settingelement.getElementsByTagName("estimation-path").item(0);
                                    Element provscriptelement = (Element) settingelement.getElementsByTagName("book-script-files-path").item(0);
                                    String estimationpath = estimationelement.getTextContent();
                                    String commonpath = commonelement.getTextContent();
                                    String provscriptpath = provscriptelement.getTextContent();
                                    AccuracyLevels al = updateacclevels(p.getPId());
                                    sr.runScript(new FileReader(provscriptpath + File.separator + p.getScriptPath()), ProviderName + "_dim", providerFile);
                                    sr.runCommonScript(new FileReader(commonpath), ProviderName + "_dim", al);
                                    sr.runEstimationScript(new FileReader(estimationpath), ProviderName + "_dim");
                                } else {
                                    Element commonelement = (Element) settingelement.getElementsByTagName("media-common-path").item(0);
                                    String commonpath = commonelement.getTextContent();
                                    Element provscriptelement = (Element) settingelement.getElementsByTagName("media-script-files-path").item(0);
                                    String provscriptpath = provscriptelement.getTextContent();
                                    AccuracyLevels al = updateacclevels(p.getPId());
                                    sr.runScript(new FileReader(provscriptpath + File.separator + p.getScriptPath()), ProviderName + "_dim", providerFile);
                                    sr.runCommonScript(new FileReader(commonpath), ProviderName + "_dim", al);
                                }
                            } else {
                                LogFile.log(" System ", " Failed to Complete the operation of downloading the file [" + ftpinfo.getFileName() + "]");
                            }
                        } else {
                            LogFile.log(" System ", " found the Remote File has Does not Change After Last Time it was Downloaded");
                        }
                    }
                } else {
                    LogFile.log(" System ", " failed to Log in to the FTP Server [" + ftpinfo.getHost() + "]");
                }
            } else {
                LogFile.log(" System ", " failed to connect to the FTP Server [" + ftpinfo.getHost() + "]");
            }
        } catch (Exception ex) {
            LogFile.log(" System ", " encoutered the Following Exception while Trying to Run FTPDownload Jar " + ex);
            ex.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
                client.disconnect();
            } catch (IOException e) {
                LogFile.log(" System ", " encoutered the Following Exception while Trying to Run FTPDownload Jar" + e);
                e.printStackTrace();
            }
        }
    }
    //method to extract Zip Files

    public void unZipFiles(String zipFileName) {
        final int BUFFER = 2048;
        try {
            LogFile.log(" System ", " started in extracting operation of required ZIP file [" + zipFileName + "]");
            BufferedOutputStream dest = null;
            FileInputStream fis = new FileInputStream(zipFileName);
            ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                String FiNa = entry.getName();
                String FileExt = FiNa.substring(FiNa.lastIndexOf("."), FiNa.length());
                String reqNam = providerName + NowDate + FileExt;
                LogFile.log(" System ", " now extracting ZIP file [" + entry.getName() + "]");
                int count;
                byte data[] = new byte[BUFFER];
                // write the files to the disk
                FileOutputStream fos = new FileOutputStream(ftpinfo.getLocalDir() + File.separator + reqNam);
                dest = new BufferedOutputStream(fos, BUFFER);
                while ((count = zis.read(data, 0, BUFFER)) != -1) {
                    dest.write(data, 0, count);
                }
                dest.flush();
                dest.close();
            }
            zis.close();
            LogFile.log(" System ", "  finished extracting operation of required ZIP file .");
        } catch (Exception e) {
            e.printStackTrace();
            LogFile.log(" System ", " encountered the following Exception while trying to Extract the ZIP file [" + e + "]");
        }
    }

    //method to extract gz files
    public void untar(InputStream in, String untarDir) {
        try {
            TarInputStream tin = new TarInputStream(in);
            TarEntry tarEntry = tin.getNextEntry();
            if (new File(untarDir).exists()) {
                LogFile.log(" System ", " started in extracting operation of required GZ file in path [" + untarDir + "]");
                while (tarEntry != null) {
                    String FiNa = tarEntry.getName();
                    String FileExt = FiNa.substring(FiNa.lastIndexOf("."), FiNa.length());
                    String reqNam = providerName + NowDate + FileExt;
                    LogFile.log(" System ", " now extracting GZ file [" + tarEntry.getName() + "]");
                    File destPath = new File(untarDir + File.separatorChar + reqNam);
                    System.out.println("Processing " + destPath.getAbsoluteFile());
                    if (!tarEntry.isDirectory()) {
                        FileOutputStream fout = new FileOutputStream(destPath);
                        tin.copyEntryContents(fout);
                        fout.close();
                    } else {
                        destPath.mkdir();
                    }
                    tarEntry = tin.getNextEntry();
                }
                tin.close();
                LogFile.log(" System ", "  finished extracting operation of required GZ file .");
            } else {
                LogFile.log(" System ", " encountered That destination directory doesn't exist! " + untarDir);
            }
        } catch (FileNotFoundException ex) {
            LogFile.log(" System ", " encountered the following Exception while trying to Extract the GZ file [" + ex + "]");
        } catch (IOException ex) {
            LogFile.log(" System ", " encountered the following Exception while trying to Extract the GZ file [" + ex + "]");
        }
    }

    //method to extract Tar Files
    public void untarBaseUpgradeFile(String tarFile, String dest) {
        try {
            LogFile.log(" System ", " started extracting operation of TAR file [" + tarFile + "]");
            TarInputStream tin = new TarInputStream(new FileInputStream(tarFile));
            TarEntry tarEntry = tin.getNextEntry();
            while (tarEntry != null) {
                String FiNa = tarEntry.getName();
                String FileExt = FiNa.substring(FiNa.lastIndexOf("."), FiNa.length());
                String reqNam = providerName + NowDate + FileExt;
                File destPath = new File(dest + File.separatorChar + reqNam);
                if (tarEntry.isDirectory()) {
                    destPath.mkdir();
                } else {
                    LogFile.log(" System ", " now extracting TAR file [" + tarEntry.getName() + "]");
                    FileOutputStream fout = new FileOutputStream(destPath);
                    tin.copyEntryContents(fout);
                    fout.close();
                }
                tarEntry = tin.getNextEntry();
            }
            tin.close();
            tin = null;
            LogFile.log(" System ", "  finished extracting operation of required TAR file");
        } catch (FileNotFoundException ex) {
            LogFile.log(" System ", " encountered the following Exception while trying to Extract the TAR file [" + ex + "]");
        } catch (IOException ex) {
            LogFile.log(" System ", " encountered the following Exception while trying to Extract the TAR file [" + ex + "]");
        }
    }

    //method to get Accuracy Levels of Certain Provider
    public AccuracyLevels updateacclevels(int alId) {
        AccuracyLevelsDao ald = new AccuracyLevelsDao(c);
        AccuracyLevels al = ald.getById(alId);
        return al;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        FtpDownload ftp = new FtpDownload(args[0]);
        if (ftpinfo.getFileExtension().equalsIgnoreCase("zip") || ftpinfo.getFileExtension().equalsIgnoreCase("tar") || ftpinfo.getFileExtension().equalsIgnoreCase("gz")) {
            UtilityClass dzf = new UtilityClass(localFilePath);
        } else {
            UtilityClass dz = new UtilityClass(FiNa, newName);
        }
    }
}
